<?php

namespace tpext\builder\traits\actions;

use tpext\builder\displayer;
use tpext\builder\logic\Export;
use tpext\builder\table\TColumn;

/**
 * 导出
 */

trait HasExport
{
    /**
     * 导出时在这里面的是允许的，其余都不允许
     *
     * @var array
     */
    protected $exportOnly = [];

    /**
     * 导出时在这里面的是不允许的，其余都允许
     *
     * @var array
     */
    protected $exportExcept = [];

    public function export()
    {
        ini_set('max_execution_time', 0);

        if ($path = input('get.path')) { //文件下载
            $filePath = RUNTIME_PATH . 'export/' . $path;
            if (!is_file($filePath)) {
                exit('<h3>文件不存在</h3>' . 'runtime/export/' . $path);
            }

            $ftime = filectime($filePath) ?: 0;

            if (time() - $ftime > 24 * 60 * 60) {
                exit('<h3>文件已过期</h3>有效期为一天');
            }

            $name = preg_replace('/\d+\/(.+?\.\w+)$/', '$1', $path);

            $file_r = fopen($filePath, "r");
            //输入文件标签
            Header("Content-type: application/octet-stream");
            Header("Accept-Ranges: bytes");
            Header("Accept-Length: " . filesize($filePath));
            Header("Content-Disposition: attachment; filename=" . $name);
            echo fread($file_r, filesize($filePath));
            fclose($file_r);
            exit;
        }

        if (input('get.big') == 1) {
            return $this->exportdBig();
        }

        request()->post(request()->get()); //兼容以post方式获取参数

        $this->isExporting = true;
        $this->table = $this->builder()->table();
        $sortOrder = input('get.__sort__', $this->sortOrder ? $this->sortOrder : $this->getPk() . ' desc');

        $__ids__ = input('get.__ids__');

        if (!empty($__ids__)) {
            $where = [[$this->getPk(), 'in', array_filter(explode(',', $__ids__))]];
        } else {
            $where = $this->filterWhere();
        }

        if ($this->dataModel) {
            if (method_exists($this->dataModel, 'asTreeList')) { //如果此模型使用了`tpext\builder\traits\TreeModel`,显示为树形结构

                $this->table->sortable([]);
                $data = $this->dataModel->getLineData();

                if ($this->isExporting) {
                    if (!empty($__ids__)) {
                        $ids = explode(',', $__ids__);
                        $newd = [];
                        foreach ($data as $d) {
                            if (in_array($d[$this->getPk()], $ids)) {
                                $newd[] = $d;
                            }
                        }
                        $data = $newd;
                    }
                }

                $this->buildTable($data);
            } else {
                $where = function ($query) use ($where) {
                    foreach ($where as $k => $v) {
                        if (is_array($v)) {
                            call_user_func_array([$query, 'where'], $v);
                        } else {
                            $query->where($v);
                        }
                    }
                };

                $list = $this->dataModel->with($this->indexWith)->where($where)->order($sortOrder)->select();
                $data = [];

                foreach ($list as $li) {
                    $data[] = $li;
                }

                // TODO 真正发挥cursor的性能优势

                $this->buildTable($data);
            }
        } else {
            $data = $this->buildDataList();
        }

        $cols = $this->table->getCols();

        $displayers = $this->getDisplayers($cols);

        $__file_type__ = input('get.__file_type__', '');

        $logic = new Export;

        if ($__file_type__ == 'xls' || $__file_type__ == 'xlsx') {
            return $logic->toExcel($this->pageTitle, $data, $displayers, $__file_type__);
        } else if ($__file_type__ == 'csv') {
            return $logic->toCsv($this->pageTitle, $data, $displayers);
        } else if ($__file_type__ == 'big') {
            return json(['code' => 1, 'open_url' => url('export')]);
        } else {
            return $this->exportTo($data, $displayers, $__file_type__);
        }
    }

    /**
     * Undocumented function
     *
     * @param string $fileType 其他类型的导出
     * @return mixed
     */
    protected function exportTo($data, $displayers, $__file_type__)
    {
        $logic = new Export;
        return $logic->toCsv($this->pageTitle, $data, $displayers);
    }

    private function getDisplayers($cols, $displayers = [], $isInFields = false)
    {
        $displayer = null;

        $fieldName = '';

        foreach ($cols as $col) {

            $displayer = $col->getDisplayer();

            $fieldName = $displayer->getName();

            if (!$isInFields && !empty($this->exportOnly) && !in_array($fieldName, $this->exportOnly)) {
                continue;
            }

            if (!empty($this->exportExcept) && in_array($fieldName, $this->exportExcept)) {
                continue;
            }

            if ($displayer instanceof displayer\Fields) {
                $content = $displayer->getContent();
                $displayers = $this->getDisplayers($content->getCols(), $displayers, true);
                continue;
            }

            if (!$col instanceof TColumn) {
                continue;
            }

            if ($displayer instanceof displayer\Checkbox || $displayer instanceof displayer\MultipleSelect) {

                $displayer = (new displayer\Matches($fieldName, $col->getLabel()))->options($displayer->getOptions());
            } else if ($displayer instanceof displayer\Radio || $displayer instanceof displayer\Select) {

                $displayer = (new displayer\Matche($fieldName, $col->getLabel()))->options($displayer->getOptions());
            } else if ($displayer instanceof displayer\SwitchBtn) {

                $pair = $displayer->getPair();
                $options = [$pair[0] => '是', $pair[1] => '否'];
                $displayer = (new displayer\Matche($fieldName, $col->getLabel()))->options($options);
            }
            $displayers[] = $displayer;
        }

        return $displayers;
    }

    /**
     * Undocumented function
     *
     * @return mixed
     */
    private function exportdBig()
    {
        ini_set('max_execution_time', 0);

        request()->post(request()->get()); //兼容以post方式获取参数

        $this->isExporting = false;
        $this->table = $this->builder()->table();
        $data = [];
        $__ids__ = input('get.__ids__');

        $buildTable = false;
        $isOver = false;

        if (!empty($__ids__)) {
            $where = [[$this->getPk(), 'in', array_filter(explode(',', $__ids__))]];
        } else {
            $where = $this->filterWhere();
        }

        $sortOrder =  $this->getPk() . ' asc';
        $page = input('get.__export_page__/d', 0);

        if ($page == 0) {
            $req = request()->get();
            $req['__export_page__'] = 1;
            $url = url('export') . '?' . http_build_query($req);

            return  '<!DOCTYPE html><html lang="zh">'
                . '<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no" /><title>导出</title>'
                . '<style>html,body{width:100%;height:100%;padding:0;margin:0;overflow:hidden;}</style>'
                . '</head><body>'
                . '<div style="400px;height:100%;margin:0 2%;text-align:center;">'
                . '<img src="/assets/tpextbuilder/js/layer/theme/default/loading-1.gif" style="margin-left:45%;"><br><p style="padding:10px 20px;color:green;">生成数据中...</p></div>'
                . "<script>location.href='{$url}';</script>"
                . '</body></html>';
        }
        $page = $page < 1 ? 1 : $page;

        $this->pagesize = 50;
        $total = 0;

        if ($this->dataModel) {
            if (method_exists($this->dataModel, 'asTreeList')) { //如果此模型使用了`tpext\builder\traits\TreeModel`,显示为树形结构

                $this->table->sortable([]);
                $data = $this->dataModel->getLineData();

                if ($this->isExporting) {
                    if (!empty($__ids__)) {
                        $ids = explode(',', $__ids__);
                        $newd = [];
                        foreach ($data as $d) {
                            if (in_array($d[$this->getPk()], $ids)) {
                                $newd[] = $d;
                            }
                        }
                        $data = $newd;
                    }
                }

                $this->buildTable($data);
            } else {
                $where = function ($query) use ($where) {
                    foreach ($where as $k => $v) {
                        if (is_array($v)) {
                            call_user_func_array([$query, 'where'], $v);
                        } else {
                            $query->where($v);
                        }
                    }
                };

                $list = $this->dataModel->with($this->indexWith)->where($where)->order($sortOrder)->limit(($page - 1) * $this->pagesize, $this->pagesize)->select();

                $total = $this->dataModel->with($this->indexWith)->where($where)->count();
                $data = [];

                foreach ($list as $li) {
                    $data[] = $li;
                }

                // TODO 真正发挥cursor的性能优势

                $this->buildTable($data);
            }
        } else {
            $data = $this->buildDataList();
        }

        if ($data instanceof \Iterator) {
            $newArr = [];
            foreach ($data as $d) {
                $newArr[] = $d;
            }
            $data = $newArr;
        }

        $rowSize = count($data);

        $this->isExporting = false;

        $buildTable = true;
        $isOver = $rowSize < $this->pagesize; //判断是否全部导出了

        if (!empty($__ids__)) {
            $ids = explode(',', $__ids__);
            $newd = [];
            foreach ($data as $d) {
                if (in_array($d[$this->getPk()], $ids)) {
                    $newd[] = $d;
                }
            }
            $data = $newd;
        }

        if ($buildTable) {
            $this->buildTable($data, true);
        }

        $cols = $this->table->getCols();

        $displayers = $this->getDisplayers($cols);

        $logic = new Export;

        $dir = RUNTIME_PATH . 'export/' . date('Ymd') . '/';

        if (!is_dir($dir)) {
            if (!mkdir($dir, 0755, true)) {
                return json(['code' => 0, 'msg' => '创建目录失败']);
            }
        }

        $__filename__ = input('get.__filename__', date('Ymd-His') . mt_rand(100, 999));

        $pathinfo = [
            'dir' => $dir,
            'name' => $__filename__,
            'start' => $this->pagesize * ($page - 1)
        ];

        $resData = [];
        $resData = $logic->toExcelBig($this->pageTitle, $data, $displayers, $pathinfo);

        if ($resData['code'] == 1) {
            if ($isOver) {
                $path = $resData['data'];
                $name = preg_replace('/.+?([^\/]+)$/', '$1', $path);
                $url = url('export') . '?path=' . $path;

                return  '<!DOCTYPE html><html lang="zh">'
                    . '<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no" /><title>导出</title>'
                    . '<style>html,body{width:100%;height:100%;padding:0;margin:0;overflow:hidden;}</style>'
                    . '</head><body>'
                    . '<div class="alert alert-success " role="alert" style="width:400px;margin:2%;">'
                    . "<script>setTimeout(function(){location.href='{$url}';},500)</script>"
                    . '<p>文件已生成，如果没有自动下载，点击下载：</p><a href="' . $url . '">' . $name . '</a><p>下载完成后请关闭此页面</p></div>'
                    . '</body></html>';
            } else {
                $sumary = ($this->pagesize * $page) . '/' . $total;

                $page += 1;
                $req = request()->get();
                $req['__export_page__'] = $page;
                $req['__filename__'] = $__filename__;
                $req['__export_pageszie__'] = $this->pagesize;
                $url = url('export') . '?' . http_build_query($req);

                return  '<!DOCTYPE html><html lang="zh">'
                    . '<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no" /><title>导出</title>'
                    . '<style>html,body{width:100%;height:100%;padding:0;margin:0;overflow:hidden;}</style>'
                    . '</head><body>'
                    . '<div style="width:400px;height:100%;margin:0 2%;text-align:center;">'
                    . '<img src="/assets/tpextbuilder/js/layer/theme/default/loading-1.gif" style="margin-left:45%;"><br><p style="padding:10px 20px;color:green;">生成数据中:' . $sumary . '...</p></div>'
                    . "<script>location.href='{$url}';</script>"
                    . '</body></html>';
            }
        } else {
            return  '<!DOCTYPE html><html lang="zh">'
                . '<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1, user-scalable=no" /><title>导出</title>'
                . '<style>html,body{width:100%;height:100%;padding:0;margin:0;overflow:hidden;}</style>'
                . '</head><body>'
                . '<div class="alert alert-success " role="alert" style="width:94%;margin:2%;">'
                . '<p>导出失败：</p>' . $data['msg'] . '</div>'
                . '</body></html>';
        }
    }
}
